// to run in terminal: g++ posix.cpp -o posix -l pthread

#include <iostream>
#include <stdlib.h>
#include <pthread.h>

using std::cout;
using std::endl;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
double allSum = 0;

double f1(double x)
{
    return 1;    
}

double f2(double x)
{
    return x;    
}

double f3(double x)
{
    return (1/(1+ x));
}

class IntegrationPart
{
    double m_startInterval;
    double m_endInterval;    
    double(*m_function)(double);
    int    m_delimiter;
    
public:
    IntegrationPart()
    {
        m_function = 0;
    }
    
    IntegrationPart(double a, double b, double(*function)(double), int delimiter) :
    m_startInterval(a), m_endInterval(b), m_function(function), m_delimiter(delimiter)
    {}
    
    double getStartInterval()
    {
        return  m_startInterval;
    }
    
    double getEndInterval()
    {
        return  m_endInterval;
    }
    
    double(*getFunction())(double)
    {
        return  m_function;
    }
    
    int getDelimiter()
    {
        return  m_delimiter;
    }
};

void * integralCounting(void *ptr)
{
    IntegrationPart * myptr;
    myptr = (IntegrationPart *) ptr;   
        
    double n = double(myptr->getEndInterval() - myptr->getStartInterval()) / myptr->getDelimiter();
    double sum = 0.;   
    
    for(size_t i = 0; i < myptr->getDelimiter(); ++i)    
        sum += myptr->getFunction()(myptr->getStartInterval() + (i + 0.5) * n);
       
    sum *= n;    
    
    pthread_mutex_lock( &mutex);
    allSum += sum;
    pthread_mutex_unlock( &mutex);
}

int main(int c, char ** arg)
{   
    if (c != 5)
    {
        cout << "Enter interval's limits, number of delimiter sections, number of threads" << endl;
        return 0;
    }
    
    double a = atof(arg[1]);
    double b = atof(arg[2]);
    int nDelimiter = atoi(arg[3]);
    int nThreads = atoi(arg[4]);
   
    if (b < a)
    {
        cout << "'a' must be less than 'b'" << endl;
        return 0;
    }
    
    IntegrationPart *masIntegPart[nThreads];
    pthread_t masThread[nThreads];    
    for (size_t i = 0; i < nThreads; ++i)
    {
        masIntegPart[i] = new IntegrationPart(a + i*(b-a)/nThreads, a + (i+1)*(b-a)/nThreads, f2, nDelimiter);        
	    pthread_create (&masThread[i], NULL, integralCounting, (void *)masIntegPart[i]);	    	    	 
    }
    
    for (size_t i = 0; i < nThreads; ++i)    
        pthread_join (masThread[i], NULL);        
        
    for (size_t i = 0; i < nThreads; ++i)
      delete masIntegPart[i];   
	
	cout << "The integral value = "<< allSum << endl;   
    
    return 0;
}
